const logger = require('../utils/logger');

/**
 * 全局错误处理中间件
 * @param {Error} err - 错误对象
 * @param {object} req - 请求对象
 * @param {object} res - 响应对象
 * @param {function} next - 下一个中间件函数
 */
const errorHandler = (err, req, res, next) => {
  // 记录错误日志
  logger.error('应用错误', {
    error: err.message,
    stack: err.stack,
    method: req.method,
    url: req.url,
    ip: req.ip,
    userAgent: req.get('User-Agent'),
    timestamp: new Date().toISOString()
  });

  // 设置默认错误状态码
  let statusCode = err.statusCode || 500;
  let message = err.message || '服务器内部错误';

  // 根据错误类型设置不同的状态码和消息
  if (err.name === 'ValidationError') {
    statusCode = 400;
    message = '请求数据验证失败';
  } else if (err.name === 'UnauthorizedError') {
    statusCode = 401;
    message = '未授权访问';
  } else if (err.name === 'ForbiddenError') {
    statusCode = 403;
    message = '禁止访问';
  } else if (err.name === 'NotFoundError') {
    statusCode = 404;
    message = '资源不存在';
  } else if (err.name === 'ConflictError') {
    statusCode = 409;
    message = '资源冲突';
  } else if (err.name === 'TooManyRequestsError') {
    statusCode = 429;
    message = '请求过于频繁';
  }

  // 生产环境下不暴露错误堆栈
  const errorResponse = {
    success: false,
    error: message,
    timestamp: new Date().toISOString(),
    path: req.url,
    method: req.method
  };

  // 开发环境下添加错误堆栈信息
  if (process.env.NODE_ENV === 'development') {
    errorResponse.stack = err.stack;
    errorResponse.details = err.message;
  }

  // 发送错误响应
  res.status(statusCode).json(errorResponse);
};

/**
 * 异步错误包装器
 * @param {function} fn - 异步函数
 * @returns {function} 包装后的函数
 */
const asyncHandler = (fn) => {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

/**
 * 404错误处理
 * @param {object} req - 请求对象
 * @param {object} res - 响应对象
 */
const notFoundHandler = (req, res) => {
  logger.warn('404错误', {
    method: req.method,
    url: req.url,
    ip: req.ip,
    userAgent: req.get('User-Agent')
  });

  res.status(404).json({
    success: false,
    error: '接口不存在',
    message: `无法找到 ${req.method} ${req.url}`,
    timestamp: new Date().toISOString(),
    suggestions: [
      '检查URL拼写是否正确',
      '确认HTTP方法是否正确',
      '查看API文档获取正确的接口地址'
    ]
  });
};

/**
 * 请求超时处理
 * @param {number} timeout - 超时时间（毫秒）
 * @returns {function} 超时中间件
 */
const timeoutHandler = (timeout = 30000) => {
  return (req, res, next) => {
    const timer = setTimeout(() => {
      logger.warn('请求超时', {
        method: req.method,
        url: req.url,
        timeout: timeout
      });

      if (!res.headersSent) {
        res.status(408).json({
          success: false,
          error: '请求超时',
          message: `请求处理时间超过 ${timeout}ms`,
          timestamp: new Date().toISOString()
        });
      }
    }, timeout);

    // 请求完成时清除定时器
    res.on('finish', () => clearTimeout(timer));
    res.on('close', () => clearTimeout(timer));

    next();
  };
};

/**
 * 请求大小限制处理
 * @param {object} req - 请求对象
 * @param {object} res - 响应对象
 * @param {function} next - 下一个中间件函数
 */
const requestSizeHandler = (req, res, next) => {
  const contentLength = parseInt(req.headers['content-length'] || '0');
  const maxSize = 10 * 1024 * 1024; // 10MB

  if (contentLength > maxSize) {
    logger.warn('请求体过大', {
      method: req.method,
      url: req.url,
      contentLength: contentLength,
      maxSize: maxSize
    });

    return res.status(413).json({
      success: false,
      error: '请求体过大',
      message: `请求体大小不能超过 ${maxSize / (1024 * 1024)}MB`,
      currentSize: `${(contentLength / (1024 * 1024)).toFixed(2)}MB`,
      maxSize: `${maxSize / (1024 * 1024)}MB`,
      timestamp: new Date().toISOString()
    });
  }

  next();
};

module.exports = {
  errorHandler,
  asyncHandler,
  notFoundHandler,
  timeoutHandler,
  requestSizeHandler
};
